package com.wwcom.darteagle.model;

import java.util.ArrayList;
import java.util.List;

public class Leg {
	private MatchInfo matchInfo;
	private List<LegPlayer> playerLegHistorys;
	private List< List<VisitScore> > legHistory;
	private List<VisitScore> currentScores;
	private boolean isLegWon;
	private int legInd;
	private List<MatchPlayer> matchPlayers;
	private MatchPlayer legWinner;
	private MatchPlayer startPlayer;
	private List<DartStats> playerStats;	
	
		
	public Leg(MatchInfo matchInfo, List<MatchPlayer> matchPlayers, MatchPlayer startPlayer, int legInd) {
		initialiseSelf();
		this.matchInfo= matchInfo;
		playerLegHistorys= new ArrayList<LegPlayer>();	
		for (MatchPlayer mp : matchPlayers) {
			playerLegHistorys.add(new LegPlayer(matchInfo,mp));
			playerStats.add( new DartStats(matchInfo,mp,-1,legInd));
		}
		this.legInd= legInd;
		this.startPlayer= startPlayer;	
		this.matchPlayers= matchPlayers;
	}
	
	private void initialiseSelf() {
		playerLegHistorys= null;
		legHistory= new ArrayList< List<VisitScore> >();
		currentScores= new ArrayList< VisitScore >();
		playerStats= new ArrayList< DartStats >();
		isLegWon= false;
		legWinner= null;
		startPlayer= null;
		matchInfo= null;
		matchPlayers= null;
	}

	//accessors
	public boolean isLegWon() {
		return isLegWon;
	}

	public MatchPlayer getLegWinner() {
		return legWinner;
	}
	
	
	//display and messages
	public List< List<VisitScore> > getLegHistory( ) {
		return legHistory;
	}
	
	public void updateLegHistory( List<MatchPlayer> matchPlayers ) {
		//copy each player visit score into a list of lists, visit-wise 
		// rather than player-wise
		
		//work out how many visits we've had so far
		int nVisits= 0;
		for (MatchPlayer mp : matchPlayers) {
			LegPlayer plh= findPlayerLegHistory(mp);
			if (plh.getVisitScores().size() > nVisits)
				nVisits= plh.getVisitScores().size();
		}
		
		//put the appropriate visits into the list into the lists in the right places
		for (int i= 0; i<nVisits; i++) {
			List<VisitScore> vsl;
			if (legHistory.size() > i) {
				vsl= legHistory.get(i);
			} else {
				vsl= new ArrayList<VisitScore>(matchPlayers.size());
			}
			int playerInd= 0;
			for (MatchPlayer mp : matchPlayers) {
				LegPlayer plh= findPlayerLegHistory(mp);
				List<VisitScore> pvsl= plh.getVisitScores();
				VisitScore vs= null;
				if (pvsl.size() > i) {
					vs= pvsl.get(i);
				} 
				//only add finalised visit scores
				if (vs != null && !vs.isFinalised())
					vs= null;
				//put into the list
				if (vsl.size()>playerInd)
					vsl.set(playerInd,vs);
				else {
					vsl.add(vs);
				}
				playerInd++;
			}			
			if (legHistory.size() > i) {
				legHistory.set(i, vsl);
			} else {				
				legHistory.add(vsl);
			}
		}
		
		return;
	}	
	
	public List<VisitScore> getPlayerCurrentScores( ) {
		return currentScores;
	}
	
	public void updatePlayerCurrentScores( List<MatchPlayer> matchPlayers ) {
		//copy each players latest visit score into a list
		//put the appropriate visits into the list in the right places
		int playerInd= 0;
		for (MatchPlayer mp : matchPlayers) {
			LegPlayer plh= findPlayerLegHistory(mp);
			if (currentScores.size() > playerInd)
				currentScores.set(playerInd, plh.getCurrentVisitScore());
			else
				currentScores.add(plh.getCurrentVisitScore());
			playerInd++;
		}
		return;
	}	

	//scoring logic
	public void updatePlayerVisitScore( MatchPlayer matchPlayer, Score score ) {
		LegPlayer plh= findPlayerLegHistory(matchPlayer);
		plh.updateCurrentVisitScore(score);
	}	
	
	public void updatePlayerVisitScore( MatchPlayer matchPlayer, int visitInd, Score score ) {
		LegPlayer plh= findPlayerLegHistory(matchPlayer);
		plh.updateVisitScore(visitInd,score);
	}		
	
	public VisitScore getPlayerVisitScore( MatchPlayer matchPlayer) {
		LegPlayer plh= findPlayerLegHistory(matchPlayer);
		return plh.getCurrentVisitScore();
	}	
	
	public VisitScore getPlayerVisitScore( MatchPlayer matchPlayer, int visitInd) {
		LegPlayer plh= findPlayerLegHistory(matchPlayer);
		if (plh.getVisitScores().size() > visitInd)
			return plh.getVisitScores().get(visitInd);
		throw new RuntimeException("Leg::getPlayerVisitScore - visitInd out of bounds");
	}		
	
	public void finalisePlayerVisitScore( MatchPlayer matchPlayer ) {
		LegPlayer plh= findPlayerLegHistory(matchPlayer);
		plh.finaliseCurrentVisitScore();
				
		//workout if the leg is won
		VisitScore vs= plh.getLastFinalisedVisitScore();
		if (vs.getLegScore() == 0) {
			isLegWon= true;
			legWinner= matchPlayer;
		}
		
		//add player leg stats
		addPlayerStatistics(matchPlayer,vs);
	}
	
	public void finalisePlayerVisitScore( MatchPlayer matchPlayer, int visitInd ) {
		LegPlayer plh= findPlayerLegHistory(matchPlayer);
		
		//finalise this visit
		plh.finaliseVisitScore(visitInd);
		
		//now go through the following visits and update
		List<VisitScore> visits= plh.getVisitScores();
		for (int vi= visitInd+1; vi < visits.size(); vi++) {
			VisitScore vsPrev= visits.get(vi-1);
			VisitScore vs= visits.get(vi);			
			vs.setLastVisit(vsPrev);
		}
		
		//workout if the leg is won
		VisitScore vs= plh.getLastFinalisedVisitScore();		
		if (vs.getLegScore() == 0) {
			isLegWon= true;
			legWinner= matchPlayer;
		}
		
		updatePlayerStatistics(matchPlayer);
	}

	public void unFinalisePlayerVisitScore( MatchPlayer matchPlayer, int visitInd ) {
		LegPlayer plh= findPlayerLegHistory(matchPlayer);
		
		//unfinalise this visit
		plh.unFinaliseVisitScore(visitInd);
	}	
	
	private LegPlayer findPlayerLegHistory(MatchPlayer matchPlayer) {
		for (LegPlayer plh : playerLegHistorys) {
			if (plh.getMatchPlayer().equals(matchPlayer))
				return plh;
		}
		return null;
	}
	
	//statistics
	public List<DartStats> getPlayerStats() {
		return playerStats;
	}
	
	private void addPlayerStatistics(MatchPlayer matchPlayer, VisitScore visitScore) {
		for (DartStats ds : playerStats) {
			if (ds.getMatchPlayer().equals(matchPlayer)) {
				ds.addDartStats(visitScore);
				break;
			}
		}
	}	
	
	public void updatePlayerStatistics(MatchPlayer matchPlayer) {
		LegPlayer plh= findPlayerLegHistory(matchPlayer);
		for (DartStats ds : playerStats) {			
			if (ds.getMatchPlayer().equals(matchPlayer)) {
				ds= new DartStats(matchInfo,matchPlayer,-1,legInd);
				for (VisitScore vs : plh.getVisitScores()) {
					if (vs.isFinalised())
						ds.addDartStats(vs);
				}
				break;
			}
		}
	}
	
	//database serialisation
	public List<VisitScore> getAllVisitScoresInVisitOrder() {
		//output leg history in visit order
		List<VisitScore> visitScores= new ArrayList<VisitScore>();
		int startPlayerInd= matchPlayers.indexOf(startPlayer);
		for (List<VisitScore> vsl : legHistory) {
			for (int i= startPlayerInd; i<vsl.size(); i++) {
				VisitScore vs= vsl.get(i); 
				if (vs != null && vs.isFinalised()) {
					visitScores.add(vs);
				}
			}
			for (int i= 0; i<startPlayerInd; i++) {
				VisitScore vs= vsl.get(i); 
				if (vs != null && vs.isFinalised()) {
					visitScores.add(vs);
				}
			}
		}
		return visitScores;
	}
}
